/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.aseclipse.core.runtime.registry.classes {

import org.aseclipse.core.runtime.registry.classes.BundleModel;
import org.aseclipse.core.runtime.registry.classes.Factory;

public class ExtensionsParser {

	// concrete object factory
	private var factory:Factory;

	// File name for this extension manifest
	// This to help with error reporting
	private var locationName:String = null;

	/** 
	 * Status code constant (value 1) indicating a problem in a bundle extensions
	 * manifest (<code>extensions.xml</code>) file.
	 */
	public static const PARSE_PROBLEM:int = 1;
	// Valid States
	private var manifestType:String;

	public function ExtensionsParser(factory:Factory) {
		super();
		this.factory = factory;
	}

	/******
	 * 
	 */  
	public function parseBundle(content:XML, manifestType:String):BundleModel {
	    if (!manifestType==(RegistryConstants.PLUGIN) && !manifestType==(RegistryConstants.FRAGMENT))
				throw new Error("Invalid manifest type: " + manifestType);
		this.manifestType = manifestType;		
		var model:BundleModel = this.factory.createBundle();
		var id:String = String(content.attribute(RegistryConstants.PLUGIN_ID));
		if(id != null && id != "") {
		    model.setUniqueIdentifier(id);
		}
		/* var name:String = String(content.attribute(PLUGIN_NAME));
		if(name != null && name != "") {
		    model.setName(name);
		} */
		var claz:String = String(content.attribute(RegistryConstants.PLUGIN_CLASS));
		if(claz != null && claz != "") {
		    model.setPluginActivator(claz);
		}
		processPlugin(model, content.children());
		return model;
	}
	
	private function processPlugin(model:BundleModel, content:XMLList):void {
	    for each(var item:XML in content) {
	        var itemTag:String = item.localName();
	        switch(itemTag) {
	            case RegistryConstants.PLUGIN_REQUIRES:
	                // 
	                processRequires(model, item);
	                break;
	            case RegistryConstants.RUNTIME:
	                //
	                processRuntime(model, item);
	                break;
	            case RegistryConstants.EXTENSION_POINT:
	                var point:ExtensionPoint = factory.createExtensionPoint();
	                point.setName(String(item.attribute(RegistryConstants.EXTENSION_POINT_NAME)));
	                point.setSimpleIdentifier(String(item.attribute(RegistryConstants.EXTENSION_POINT_ID)));
	                point.setSchema(String(item.attribute(RegistryConstants.EXTENSION_POINT_SCHEMA)));
	                point.setParent(model);
	                model.addExtensionPoint(point);
	                break;
	            case RegistryConstants.EXTENSION:
	                var extension:Extension = factory.createExtension();
	                extension.setParent(model);
	                extension.setName(String(item.attribute(RegistryConstants.EXTENSION_NAME)));
	                extension.setSimpleIdentifier(String(item.attribute(RegistryConstants.EXTENSION_ID)));
	                var attrValue:String = String(item.attribute(RegistryConstants.EXTENSION_TARGET));
    				if (attrValue.lastIndexOf('.') == -1) {
    					var baseId:String = model.getUniqueIdentifier();
    					attrValue = baseId + "." + attrValue; //$NON-NLS-1$
    				}
    				extension.setExtensionPointIdentifier(attrValue);
    				model.addExtension(extension);
    				var subs:Array = null;
    				for each(var child:XML in item.children()) {
    				    if(subs == null) subs = new Array();
    				    var confElem:ConfigurationElement = factory.createConfigurationElement();
    				    confElem.setParent(extension);
    				    subs.push(confElem);
    				    processConfiguration(confElem, child);
    				}
    				extension.setSubElements(subs);
    				break;
	        }
	    }
	}
	
	private function processRequires(model:BundleModel, item:XML):void {
	    var imports:XMLList = item.children();
	    if(imports == null || imports.length() == 0) return;
	    for each(var importItem:XML in imports) {
	        if(importItem.localName() == RegistryConstants.PLUGIN_REQUIRES_IMPORT) {
	            var pluginId:String = String(importItem.attribute(RegistryConstants.PLUGIN_REQUIRES_PLUGIN));
	            model.addRequirePlugin(pluginId);
	        }
	    }	    
	}
	
	private function processRuntime(model:BundleModel, item:XML):void {
        var libs:XMLList = item.children();
	    if(libs == null || libs.length() == 0) return;
	    for each(var libItem:XML in libs) {
	        var lib:String, internalUrl:String, externalUrl:String;
	        if(libItem.localName() == RegistryConstants.LIBRARY) {
	            lib = String(libItem.attribute(RegistryConstants.LIBRARY_NAME));
	            internalUrl = String(libItem.attribute(RegistryConstants.LIBRARY_INTERURL));
	            externalUrl = String(libItem.attribute(RegistryConstants.LIBRARY_EXTURL));
	            if(internalUrl != null && internalUrl != "")
    	            model.addLibrary({name:lib, isInternal:true, url:internalUrl});
    	        else
    	            model.addLibrary({name:lib, isInternal:false, url:externalUrl});
	        } else if(libItem.localName() == RegistryConstants.STYLE) {
	            lib = String(libItem.attribute(RegistryConstants.LIBRARY_NAME));
	            internalUrl = String(libItem.attribute(RegistryConstants.LIBRARY_INTERURL));
	            externalUrl = String(libItem.attribute(RegistryConstants.LIBRARY_EXTURL));
	            if(internalUrl != null && internalUrl != "")
    	            model.addStyle({name:lib, isInternal:true, url:internalUrl});
    	        else 
    	            model.addStyle({name:lib, isInternal:false, url:externalUrl});
	        } else if(libItem.localName() == RegistryConstants.LOCALE) {
	            lib = String(libItem.attribute(RegistryConstants.LIBRARY_NAME));
	            internalUrl = String(libItem.attribute(RegistryConstants.LIBRARY_INTERURL));
	            externalUrl = String(libItem.attribute(RegistryConstants.LIBRARY_EXTURL));
	            if(internalUrl != null && internalUrl != "")
    	            model.addLocale({name:lib, isInternal:true, url:internalUrl});
    	        else
    	            model.addLocale({name:lib, isInternal:false, url:externalUrl});
	        }
	    }
	}
	
	private function processConfiguration(confElem:ConfigurationElement, conf:XML):void {
	    confElem.setName(conf.localName());
	    confElem.setValue(conf.toString());
	    var attrs:Array = null;
	    for each(var item:XML in conf.attributes()) {
	        if(attrs == null)
	            attrs = new Array();
	        var pro:ConfigurationProperty = factory.createConfigurationProperty();
	        pro.setName(item.name());
	        pro.setValue(item.toString());
	        pro.setParent(confElem);
	        attrs.push(pro);
	    }
	    if(attrs != null)
	        confElem.setProperties(attrs);
	    var children:Array = null;    
	    for each(var child:XML in conf.children()) {
	        var confele:ConfigurationElement = factory.createConfigurationElement();
	        confele.setParent(confElem);
	        processConfiguration(confele, child);
	        if(children == null)
	            children = new Array();
	        children.push(confele);
	    }
	    if(children != null)
	        confElem.setChildren(children);
	} 
}
}